/*
 * User.java
 * Author: Thach Nguyen
 * Version 5/21/2011 Started Code
 * Version 5/25/2011 Streamlined get/add Class/Time methods to accept UserType.
 * Version 6/01/2011 Added myTeacherMaxCredits, and AddUserType()
 */
package user;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import data.ClassPreference;
import data.TimeSlot;

/**
 * This class represents any given user.
 * @author Thach Nguyen
 * @version June 1, 2011
 */
public class User {
	private final static String ILLEGAL_USER_TYPE = "The UserType does not match precondition.";
	private final static int DEFAULT_MAX_CREDITS = 15;
	
	private List<ClassPreference> myStudentClassPreferences;
	private List<TimeSlot> myStudentTimePreferences;
	
	private List<ClassPreference> myTeacherClassPreferences;
	private List<TimeSlot> myTeacherTimePreferences;
	private int myTeacherMaxCredits;
	
	private List<ClassPreference> myAdviserClassPreferences;
	
	private final int myUserID;
	
	private final String myName;
	
	private List<UserType> myUserTypes;
	
	public User(final int theID, final String theName, final UserType theType) {
		this(theID, theName, new UserType[]{theType});
	}
	
	public User(final int theID, final String theName, UserType[] theTypes) {
		myUserID = theID;
		myName = theName;
		myUserTypes = new ArrayList<UserType>();
		for(UserType type : theTypes) {
			makePreferenceList(type);
			myUserTypes.add(type);
		}
		myTeacherMaxCredits = DEFAULT_MAX_CREDITS;
	}
	
	/**
	 * Instantiates the preference lists needed based on theType.
	 */
	private void makePreferenceList(final UserType theType) {
		switch (theType) {
		case STUDENT:
			myStudentClassPreferences = new ArrayList<ClassPreference>();
			myStudentTimePreferences = new ArrayList<TimeSlot>();
			break;
		case TEACHER:
			myTeacherClassPreferences = new ArrayList<ClassPreference>();
			myTeacherTimePreferences = new ArrayList<TimeSlot>();
			break;
		case ADVISER:
			myAdviserClassPreferences = new ArrayList<ClassPreference>();
			break;
		default:
			break;//do nothing
		}
	}
	
	public void addUserType(final UserType theType) {
		myUserTypes.add(theType);
		makePreferenceList(theType);
	}
	
	public void addUserType(final List<UserType> theTypes){
		for (UserType type : theTypes){
			addUserType(type);
		}
	}
	
	
	/**
	 * @pre 1. getUserTypes().contains(theType);
	 * @pre 2. theType.equals(UserType.STUDENT) || theType.equals(UserType.TEACHER) ||
	 * theType.equals(UserType.ADVISER);
	 * @post getStudentClasses.contains(theClass);
	 * @throws NullPointerException if precondition 1 is not met.
	 * @throws IllegalArgumentException if precondition 2 is not met.
	 */
	 public void addClass(final ClassPreference theClass, final UserType theType) {
		switch (theType) {
		case STUDENT:
			myStudentClassPreferences.add(theClass); //Throws NullPointerException.
			break;
		case TEACHER:
			myTeacherClassPreferences.add(theClass); //Throws NullPointerException.
			break;
		case ADVISER:
			myAdviserClassPreferences.add(theClass); //Throws NullPointerException.
			break;
		default:
			throw new IllegalArgumentException(ILLEGAL_USER_TYPE);
		}
	}
	
	/**
	 * @pre 1. getUserTypes().contains(theType);
	 * @pre 2. theType.equals(UserType.STUDENT) || theType.equals(UserType.TEACHER);
	 * @post getTimes(theType).contains(theTime);
	 * @throws NullPointerException if precondition 1 is not met.
	 * @throws IllegalArgumentException if precondition 2 is not met.
	 */
	public void addTime(final TimeSlot theTime, final UserType theType) {
		switch (theType) {
		case STUDENT:
			myStudentTimePreferences.add(theTime); //Throws NullPointerException.
			break;
		case TEACHER:
			myTeacherTimePreferences.add(theTime); //Throws NullPointerException.
			break;
		default:
			throw new IllegalArgumentException(ILLEGAL_USER_TYPE);
		}
			
	}	

	/**
	 * {@inheritDoc}
	 * Specifically two Users are equal if theOther.getUserID() == getUserID().
	 */
	@Override
	public boolean equals(final Object theOther) {
		boolean result = false;
	    if (this == theOther)
	    {
	      result = true;
	    }
	    else if (theOther != null && theOther.getClass() == getClass())
	    {
	      final User temp = (User) theOther;
	      result = myUserID == temp.myUserID;
	    }
	    return result;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int hashCode() {
		return myUserID * myUserID;
	}
	
	/**
	 * @pre 1. getUserTypes().contains(theType);
	 * @pre 2. theType.equals(UserType.STUDENT) || theType.equals(UserType.TEACHER) ||
	 * theType.equals(UserType.ADVISER);
	 * @return An unmodifiable list of theType's class preferences.
	 * @throws NullPointerException if precondition 1 is not met.
	 * @throws IllegalArgumentException if precondition 2 is not met.
	 */
	public List<ClassPreference> getClasses(final UserType theType) {
		List<ClassPreference> result;
		switch (theType) {
		case STUDENT:
			result = myStudentClassPreferences;
			break;
		case TEACHER:
			result = myTeacherClassPreferences;
			break;
		case ADVISER:
			result = myAdviserClassPreferences;
			break;
		default:
			throw new IllegalArgumentException(ILLEGAL_USER_TYPE);
		}
		return Collections.unmodifiableList(result); //Throws NullPointerException.
	}

	/**
	 * @pre 1. getUserTypes().contains(theType);
	 * @pre 2. theType.equals(UserType.STUDENT) || theType.equals(UserType.TEACHER);
	 * @return An unmodifiable list of theType's time preferences.
	 * @throws NullPointerException if precondition 1 is not met.
	 * @throws IllegalArgumentException if precondition 2 is not met.
	 */
	public List<TimeSlot> getTimes(final UserType theType) {
		List<TimeSlot> result;
		switch (theType) {
		case STUDENT:
			result = myStudentTimePreferences; 
			break;
		case TEACHER:
			result = myTeacherTimePreferences;
			break;
		default:
			throw new IllegalArgumentException(ILLEGAL_USER_TYPE);
		}
		return Collections.unmodifiableList(result); //Throws NullPointerException.
	}

	/**
	 * @return A list of user types.
	 */
	public List<UserType> getUserType() { return Collections.unmodifiableList(myUserTypes); }
	
	/**
	 * @return The Identification Number of this user.
	 */
	public int getUserID() { return myUserID; }
	
	/**
	 * @return The name of this user.
	 */
	public String getName() { return myName; }	
	
	public void setMyMaxCredits(final int theMaxCredits) { myTeacherMaxCredits = theMaxCredits; }

	public int getMyMaxCredits() { return myTeacherMaxCredits;	}
	

}
